##########################################
## Copyright 2012-2013 Ceruti Francesco
##
##
## This file is part of LiSP (Linux Show Player).
##
## LiSP (Linux Show Player) is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## LiSP (Linux Show Player) is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with LiSP (Linux Show Player).  If not, see <http://www.gnu.org/licenses/>.
##########################################

from PyQt4 import QtGui, QtCore
from lisp.core.plugin import Plugin
from lisp.ui.preferences.preferences_widget import PreferencesWidget
from lisp.midi.midi import MidiEvent


class Controller(Plugin):

    PLUGIN_NAME = 'Controller'

    def __init__(self, main):
        super(Controller, self).__init__(main)

        self.collector = main.collector
        self.main = main
        self.handler = main.midiHandler

        if(main.midiHandler is not None):
            self.handler.midiReaded.connect(self.onMidiEvent)
            ControllerPreferences.handler = self.handler

        self.reset()

        self.collector.onMediaAdded.connect(self.connectMedia)

    def reset(self):
        self.layout = self.main.collectorUi
        self.layout.onKeyPressed.connect(self.onKeyPressed)
        self.layout.registerSettingsWidget(ControllerPreferences)

        self.__map = {}
        if(self.handler is not None):
            self.handler.reset()

    def reload(self):
        self.reset()

        for media in self.collector.media:
            if(media.state != media.NONE):
                self.updateMap(media)

    def connectMedia(self, media):
        media.onConfigurationChanged.connect(self.updateMap)

    def getData(self):
        return {'device': self.handler.device}

    def setData(self, conf):
        if(self.handler is not None):
            self.handler.changeDevice(conf['device'])

    def updateMap(self, media):
        self.deleteFromMap(media)

        if('hotkey' in media.conf):
            if(media.conf['hotkey'] == ''):
                media.conf.pop('hotkey')
            else:
                if(media.conf['hotkey'] not in self.__map):
                    self.__map[media.conf['hotkey']] = []
                if(media not in self.__map[media.conf['hotkey']]):
                    self.__map[media.conf['hotkey']].append(media)

        if('midi' in media.conf):
            if(media.conf['midi'] == ''):
                media.conf.pop('midi')
            else:
                if(media.conf['midi'] not in self.__map):
                    self.__map[media.conf['midi']] = []
                if(media not in self.__map[media.conf['midi']]):
                    self.__map[media.conf['midi']].append(media)

    def deleteFromMap(self, media):
        for key in self.__map.keys():
            for m in self.__map[key]:
                if(m == media):
                    self.__map[key].remove(m)
                    return

    def onKeyPressed(self, keyEvent):
        self.performAction(keyEvent.text())

    def onMidiEvent(self, event):
        event.timestamp = 0
        self.performAction(event.toString())

    def performAction(self, key):
        if(key in self.__map and key != ''):
            for media in self.__map[key]:
                self.layout.performNextMediaAction(media)


class ControllerPreferences(PreferencesWidget):

    NAME = 'MIDI and Hot-Key'

    handler = None

    def __init__(self, size, parent=None):
        super(ControllerPreferences, self).__init__(size, parent)

        self.verticalLayout = QtGui.QVBoxLayout(self)

        self.keyGroup = QtGui.QGroupBox(self)
        self.keyGroup.setTitle('Keyboard input')

        self.horizontalLayout = QtGui.QHBoxLayout(self.keyGroup)

        self.key = QtGui.QLineEdit(self.keyGroup)
        self.key.setMaxLength(1)
        self.horizontalLayout.addWidget(self.key)

        self.keyLabel = QtGui.QLabel('Insert the key', self.keyGroup)
        self.horizontalLayout.addWidget(self.keyLabel)

        self.verticalLayout.addWidget(self.keyGroup)

        self.midiGroup = QtGui.QGroupBox(self)
        self.midiGroup.setTitle('MIDI')

        self.midiLayout = QtGui.QGridLayout(self.midiGroup)

        self.midiChannels = QtGui.QLineEdit(self.midiGroup)
        self.midiChannels.setValidator(QtGui.QRegExpValidator(QtCore.QRegExp('(([1-9]|1[0-6]),)*')))
        self.midiChannels.setText('1')
        self.midiLayout.addWidget(self.midiChannels, 0, 0)
        self.midiLayout.addWidget(QtGui.QLabel('Midi Channels [1,2,..,16]', self), 0, 1)

        self.midiStatus = QtGui.QSpinBox(self.midiGroup)
        self.midiStatus.setRange(0, 255)
        self.midiLayout.addWidget(self.midiStatus, 1, 0)
        self.midiLayout.addWidget(QtGui.QLabel('Status', self), 1, 1)

        self.midiData1 = QtGui.QSpinBox(self.midiGroup)
        self.midiData1.setRange(0, 255)
        self.midiLayout.addWidget(self.midiData1, 2, 0)
        self.midiLayout.addWidget(QtGui.QLabel('Data 1', self), 2, 1)

        self.midiData2 = QtGui.QSpinBox(self.midiGroup)
        self.midiData2.setRange(0, 255)
        self.midiLayout.addWidget(self.midiData2, 3, 0)
        self.midiLayout.addWidget(QtGui.QLabel('Data 2', self), 3, 1)

        self.midiData3 = QtGui.QSpinBox(self.midiGroup)
        self.midiData3.setRange(0, 255)
        self.midiLayout.addWidget(self.midiData3, 4, 0)
        self.midiLayout.addWidget(QtGui.QLabel('Data 3', self), 4, 1)

        self.midiCapture = QtGui.QPushButton('Capture', self.midiGroup)
        self.midiValue = ''
        self.midiLayout.addWidget(self.midiCapture, 5, 0)

        self.takeFirst = QtGui.QCheckBox('Take only first MIDI event', self.midiGroup)
        self.takeFirst.setChecked(True)
        self.emitted = False
        self.midiLayout.addWidget(self.takeFirst, 5, 1)

        self.verticalLayout.addWidget(self.midiGroup)
        self.verticalLayout.setStretch(0, 1)
        self.verticalLayout.setStretch(1, 4)

        self.midiCapture.clicked.connect(self.captureMidi)
        self.midiChannels.textEdited.connect(self.changeMidiChannels)

    def enableCheck(self, enable):
        self.keyGroup.setCheckable(enable)
        self.keyGroup.setChecked(False)

        self.midiGroup.setCheckable(enable)
        self.midiGroup.setChecked(False)

    def getConfiguration(self):
        conf = {}
        checked = self.keyGroup.isCheckable()

        if(not (checked and not self.keyGroup.isChecked())):
            conf['hotkey'] = self.key.text()

        if(not (checked and not self.midiGroup.isChecked())):
            conf['midi'] = MidiEvent(self.midiStatus.value(), 0,
                                     [self.midiData1.value(),
                                      self.midiData2.value(),
                                      self.midiData3.value()]).toString()

        return conf

    def setConfiguration(self, conf):
        if(conf is not None):
            if('hotkey' in conf):
                self.key.setText(conf['hotkey'])
            if('midi' in conf):
                e = MidiEvent()
                e.fromString(conf['midi'])
                self.onMidiEvent(e)
            if(ControllerPreferences.handler == None):
                self.midiGroup.setEnabled(False)

    def changeMidiChannels(self):
        channels_str = self.midiChannels.text().split(',')
        channels = [int(channels_str[-1])] if channels_str[-1] != '' else []
        channels += [int(ch) for ch in channels_str[:-1]]
        if(len(channels) > 0):
            ControllerPreferences.handler.changeChannels(channels)

    def captureMidi(self):
        ControllerPreferences.handler.recordMode = True
        ControllerPreferences.handler.midiRecorded.connect(self.onMidiEvent)
        QtGui.QMessageBox.information(self, 'Input', 'Give a MIDI event and press OK')
        self.emitted = False
        ControllerPreferences.handler.midiRecorded.disconnect(self.onMidiEvent)
        ControllerPreferences.handler.recordMode = False

    def onMidiEvent(self, event):
        if(not (self.emitted and self.takeFirst.isChecked())):
            event.timestamp = 0
            self.midiStatus.setValue(event.status)
            self.midiData1.setValue(event.data[0])
            self.midiData2.setValue(event.data[1])
            self.midiData3.setValue(event.data[2])
            self.emitted = True
